/// <summary>
/// Initial idea from
/// http://dotnetjunkies.com/WebLog/principal/archive/2005/04/21/69872.aspx
/// </summary>
using System.ComponentModel;
using System.Windows.Forms;
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.Text;
namespace PrintScreen
{
        [Flags()]
        public enum KeyModifiers
        {

            None = 0,
            Alt = 1,
            Control = 2,
            AltControl = Alt+Control,
            Shift = 4,
            AltShift = Alt+ Shift,
            ControlShift = Control + Shift,
            AltControlShift  = Alt+Control+Shift ,
            Windows = 8,
            All = Alt+Control+Shift + Windows
            

        }

    public class HotKey : Component, IMessageFilter
    {
        
        [DllImport("user32.dll")]
        private static extern int GetForegroundWindow();
        [DllImport("user32.dll")]
        private static extern int GetWindowText(int hWnd, StringBuilder caption, int count);


        public event EventHandler<KeyEventArgs> HotKeyPressed;

        private List<KeyRegistered> ids;

        #region Native win32 API

        private const int WM_HOTKEY = 0x0312;

        [DllImport("user32.dll", SetLastError = true)]

        private static extern bool RegisterHotKey(IntPtr hWnd, int id, KeyModifiers fsModifiers, Keys vk);

        [DllImport("user32.dll", SetLastError = true)]

        private static extern bool UnregisterHotKey(IntPtr hWnd, int id);

        [DllImport("kernel32.dll", SetLastError = true)]
        internal static extern int GlobalAddAtom(string lpString);

        [DllImport("kernel32.dll", SetLastError = true)]
        internal static extern int GlobalDeleteAtom(int nAtom);



        #endregion
        protected override bool CanRaiseEvents
        {
            get
            {
                return true;
            }
        }
        
        private string m_FolderToSave;
        [Bindable(true), Category("Props")]
        public string FolderToSave
        {
            get
            {
                if (m_FolderToSave == null)
                    m_FolderToSave = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures);

                return m_FolderToSave;
            }
            set
            {
                m_FolderToSave = value;
            }
        }

        public event EventHandler KeyChanged;

        public event EventHandler KeyModifierChanged;

        private IntPtr handle;

        public IntPtr Handle
        {

            get { return handle; }

            set { handle = value; }

        }

        private Keys key;

        private KeyModifiers keyModifier;

        private bool isKeyRegisterd;

        public HotKey()
        {

            Application.AddMessageFilter(this);

        }
        private void RemoveHotKeys()
        {
            if (ids != null)
                foreach (KeyRegistered kd in ids)
                {
                    int id = kd.m_id;
                    GlobalDeleteAtom(id);
                    UnregisterHotKey(handle, id);
                }
            ids = null;
        }
        private void AddHotKeys()
        {
            ids = new List<KeyRegistered>();
            foreach (int i in Enum.GetValues(typeof(KeyModifiers)))
            {
                if (((int)KeyModifier & i) == i)
                {
                    int id = GlobalAddAtom("Andrei_PrintScreen_" + i + "_" + DateTime.Now.ToString("yyyyMMddhhmmss"));
                    ids.Add(new KeyRegistered(id, (KeyModifiers)i));
                }

            }

            ids.TrimExcess();
        }
        ~HotKey()
        {

            Application.RemoveMessageFilter(this);
            RemoveHotKeys();

        }

        private void RegisterHotKey()
        {


            if (key == Keys.None)
                return;
            RemoveHotKeys();
            AddHotKeys();

            foreach (KeyRegistered kd in ids)
            {
                int id = kd.m_id;
                //if (kd.m_register)
                //    isKeyRegisterd = !(UnregisterHotKey(handle, id));

                isKeyRegisterd = RegisterHotKey(handle, id, kd.m_Modifiers, key);

                kd.m_register = isKeyRegisterd;
                //TODO: list keys not capable to register
                /*
                if (!isKeyRegisterd)
                    throw new ApplicationException("Hotkey allready in use");
                */
            }
        }

        [Bindable(true), Category("HotKey")]
        public Keys Key
        {

            get { return key; }

            set
            {

                if (key != value)
                {

                    key = value;

                    OnKeyChanged(new EventArgs());

                }

            }

        }

        [Bindable(true), Category("HotKey")]
        public KeyModifiers KeyModifier
        {

            get { return keyModifier; }

            set
            {

                if (keyModifier != value)
                {

                    keyModifier = value;

                    OnKeyModifierChanged(new EventArgs());

                }

            }

        }

        public bool PreFilterMessage(ref Message m)
        {

            switch (m.Msg)
            {

                case WM_HOTKEY:

                    CaptureScreen();

                    Keys k = Key;
                    if ((Control.ModifierKeys & Keys.Alt) != 0)
                        k = k | Keys.Alt;

                    if ((Control.ModifierKeys & Keys.Shift) != 0)
                        k = k | Keys.Shift;

                    if ((Control.ModifierKeys & Keys.Control) != 0)
                        k = k | Keys.Control;


                    KeyEventArgs kd = new KeyEventArgs(k);
                    //kd.Shift = ((int)m.WParam == (int)Keys.Shift);
                    //kd.Control = ((int)m.WParam == (int)Keys.Control);
                    OnHotKeyPressed(kd);


                    break;
            }

            return false;

        }
        private ImageInfo image;
        public ImageInfo Image
        {
            get
            {
                if (image == null)
                {
                    CaptureScreen();
                }
                return image;
            }
        }
        private void CaptureScreen()
        {
            image = new ImageInfo();
            int width = SystemInformation.PrimaryMonitorSize.Width;
            int height = SystemInformation.PrimaryMonitorSize.Height;
            Rectangle r = Screen.PrimaryScreen.Bounds;
            image.Screen = new Bitmap(width, height);
            Graphics g = Graphics.FromImage(image.Screen );
            g.CopyFromScreen(r.Left, r.Top, 0, 0, r.Size);            

            int i = GetForegroundWindow();
            StringBuilder sb=new StringBuilder(256);
            GetWindowText(i, sb, sb.Capacity);
            image.ActiveWindowText = sb.ToString();
            image.ActiveWindow = new Bitmap(ScreenCapture.CaptureWindow(i));
            
            
        }

        private void OnHotKeyPressed(KeyEventArgs e)
        {

            if (HotKeyPressed != null)

                HotKeyPressed(this, e);

        }

        private void OnKeyChanged(EventArgs e)
        {

            RegisterHotKey();

            if (KeyChanged != null)

                KeyChanged(this, e);

        }

        private void OnKeyModifierChanged(EventArgs e)
        {

            RegisterHotKey();

            if (KeyModifierChanged != null)

                KeyModifierChanged(this, e);

        }

    }

    class KeyRegistered
    {
        public int m_id;
        public bool m_register = false;
        public KeyModifiers m_Modifiers;

        public KeyRegistered(int id, KeyModifiers km)
        {
            m_id = id;
            m_Modifiers = km;
        }

    }
    public class ImageInfo
    {
        public Bitmap Screen;
        public Bitmap ActiveWindow;
        public string ActiveWindowText;
        public string ValidFileName
        {
            get
            {
                string strName = ActiveWindowText.Replace("+", "").Replace("/", "").Replace(".", "").Replace("(", "").Replace(")", "").Replace("-", "");                
                strName = strName.Replace(@"\", "");
                strName = strName.Replace(@"?", "");
                strName = strName.Replace(@"*", "");
                strName = strName.Replace(@"[", "");
                strName = strName.Replace(@"]", "");
                strName = strName.Replace(@"'", "");
                strName = strName.Replace(@":", "");
                return strName;
            }
        }
    }
}